﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Logging
{
    public class SimpleLoggerFormatter
    {
        public static readonly string PERCENT = "%%";
        public static readonly string TIME = "%T";
        public static readonly string LOGGER_NAME = "%N";
        public static readonly string LEVEL = "%L";
        public static readonly string MESSAGE = "%M";

        public static readonly string DEFAULT_FORMAT_STRING = TIME + " [" + LOGGER_NAME + "] " + LEVEL + ": " + MESSAGE;

        private static IDictionary<string, SimpleLoggerFormatter> formatterCache = new Dictionary<string, SimpleLoggerFormatter>();

        public static SimpleLoggerFormatter getFormatter(string formatString)
        {
            SimpleLoggerFormatter formatter = null;
            try
            {
                formatter = formatterCache.Single(f => f.Key.Equals(formatString)).Value;
            }
            catch (Exception)
            {
                formatter = new SimpleLoggerFormatter(formatString);
                formatterCache.Add(formatString, formatter);
            }
            return formatter;
        }

        private string formatString;

        private SimpleLoggerFormatter(string formatString)
        {
            this.formatString = formatString;
        }

        public string format(SimpleLogRecord logRecord)
        {
            return formatString.Replace(PERCENT, "%")
                .Replace(TIME, logRecord.Time.ToLongDateString() + " at " + logRecord.Time.ToLongTimeString())
                .Replace(LOGGER_NAME, logRecord.LoggerName)
                .Replace(LEVEL, logRecord.Level.ToString())
                .Replace(MESSAGE, logRecord.Message + "\r\n" + ((logRecord.Exception != null) ? formatException(logRecord.Exception) : ""));
        }

        private string formatException(Exception e)
        {
            StringBuilder exceptionStringBuilder = (new StringBuilder(0x00001000))
                .Append("[")
                .Append(e.Source)
                .Append("] ")
                .Append(e.GetType().FullName)
                .Append(": ")
                .Append(e.Message)
                .Append("\r\n")
                .Append(e.StackTrace)
                .Append("\r\n");
            if (e.InnerException != null)
            {
                exceptionStringBuilder
                    .Append("Caused by ")
                    .Append(formatException(e.InnerException));
            }
            return exceptionStringBuilder.ToString();
        }
    }
}
